#include "include.h"
#include "sniffing.h"
#include "stats.h"

// Variable global utilisée pour savoir si la capture doit être arrêtée ou non
int stop_capture = FALSE;

void capture_signal(int signal)
{
	(void) signal;
	
	printf("\n* Capture interruption !\n");
	stop_capture = TRUE;
}

int
main(int argc, char** argv)
{
	char* device = NULL;
	char* filter = NULL;
	
	bpf_u_int32 network_addr;
	bpf_u_int32 network_mask;
	
	char* str_addr = NULL;
	char* str_mask = NULL;
	
	struct in_addr addr;
	
	struct bpf_program program_filter;
	
	int  return_code;
	char error_buffer[PCAP_ERRBUF_SIZE];
	
	pcap_t* handle;
	struct pcap_pkthdr* packet_header;
	const u_char*       packet_data;
	
	// Liste de statistiques de paquet
	sniff_stat* stats = NULL;
	
	struct timeval time_begin_capture;
	struct timeval time_end_capture;
	
	// Vérification de l'aide
	if (argc == 2 && (
	                  strcmp(argv[1], "-h")     == 0 ||
	                  strcmp(argv[1], "--help") == 0
	                 )
	   )
	{
		printf("Usage: sudo %s [<interface> [<filter>]]\n", argv[0]);
		exit(0);
	}
	
	printf("* Network configuration :\n");
	
	// Gestion des arguments 
	
	// Interface
	if (argc > 1)
	{		
		device = argv[1];
	}
	else
	{
		// Recherche d'une interface valide pour analyser le réseau
		if ((device = pcap_lookupdev(error_buffer)) == NULL)
		{
			fprintf(stderr, "Error : %s\n", error_buffer);
			exit(1);
		}
	}
	
	// Options/filtres
	if (argc > 2)
	{
		filter = argv[2];
	}

	// Récupération de l'adresse et du masque de l'interface
	return_code = pcap_lookupnet(device, &network_addr, &network_mask, error_buffer);
	
	if (return_code == -1)
	{
		fprintf(stderr, "Error : %s\n", error_buffer);
		exit(1);
	}
	
	// Sous forme lisible
	str_addr = malloc(16 * sizeof(char));
	str_mask = malloc(16 * sizeof(char));
	
	// Adresse
	addr.s_addr = network_addr;
	strcpy(str_addr, inet_ntoa(addr));
	if (str_addr == NULL)
	{
		perror("inet_ntoa");
		exit(1);
	}
	
	// Masque
	addr.s_addr = network_mask;
	strcpy(str_mask, inet_ntoa(addr));
	if (str_mask == NULL)
	{
		perror("inet_ntoa");
		exit(1);
	}
	
	printf("\tDevice : '%s'\n"
           "\tAdress : %s\n"
           "\tMask   : %s\n",
           device, str_addr, str_mask);

	printf("* Opening %s interface\n", device);

	// Ouverture de l'interface en mode 'promiscuous'
	handle = pcap_open_live(device, PCAP_ERRBUF_SIZE, TRUE, 200, error_buffer);
	if (handle == NULL)
	{
		fprintf(stderr, "Error : %s\n", error_buffer);
		exit(1);
	}
	
	// "Parsing" des filtres s'il y'en a
	if (filter != NULL)
	{
		printf("* Parsing \"%s\" filter\n", filter);
		
		if (pcap_compile(handle, &program_filter, filter, FALSE, network_addr) == -1)
		{
			fprintf(stderr, "Error : %s\n", pcap_geterr(handle));
			exit(1);
		}
		
		printf("* Applying filter\n");
		
		if (pcap_setfilter(handle, &program_filter) == -1)
		{
			fprintf(stderr, "Error : %s\n", pcap_geterr(handle));
			exit(1);
		}	
	}
	
	printf("* Running network analysis ... (CTRL+C to stop)\n\n");
	
	// Capture du signal SIGINT (Ctrl+C)
	signal(SIGINT, capture_signal);
	
	// Timer de début
	gettimeofday(&time_begin_capture, NULL);
	
	// Capture des paquets
	while (!stop_capture && (return_code = pcap_next_ex(handle, &packet_header, &packet_data)) >= 0)
	{
		if (return_code == 0)
		{
			// Timeout
			continue;
		}
		
		if (!stop_capture)
		{
			// Création d'une node statistiques pour le paquet qui vient
			stats = add_new_node(stats);
			// Analyse du paquet
			got_packet((u_char*) stats, packet_header, packet_data, &time_begin_capture);
		}
	}
	
	// Timer de fin
	gettimeofday(&time_end_capture, NULL);
	
	// L'utilisateur peut de nouveau quitter avec CTRL+C
	signal(SIGINT, SIG_DFL);
	
	if (return_code == -1)
	{
		printf("Error : %s\n", pcap_geterr(handle));
		exit(1);
	}
	
	// Fermeture de la session
	printf("* Capture completed\n");
	
	printf("* Statistics :\n\n");
	
	if (stats != NULL)
	{
		// On forke la programme, le père affiche, le fils écrit dans le fichier
		int file;
		pid_t pid = fork();
		
		if (pid == 0)
		{
			// On redirige la sortie vers le fichier
			if ((file = open("analysis.txt", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
			{
				printf("Error while creating \"analysis.txt\" file \n");
				exit(0);
			}
			close(1);
			dup(file);
			
			struct tm* print_time;
			char str_time[64];
			print_time = localtime(&time_begin_capture.tv_sec);
			strftime(str_time, sizeof(str_time), "%H:%M:%S %Y/%m/%d", print_time);
			
			printf("---- Network analysis - %s ---------\n", str_time);
			printf("\tDevice : '%s'\n"
				   "\tAdress : %s\n"
				   "\tMask   : %s\n",
				   device, str_addr, str_mask);
			
			if (filter)
			{
				printf("\tFilter : %s\n", filter);
			}	
			
			printf("-----------------------------------------------------\n\n");
		}
		
		// Génération des statistiques
		generate_stats(stats, &time_begin_capture, &time_end_capture);
	
		if (pid > 0)
		{
			printf("\n* These stats are available in the file \"analysis.txt\"\n");
		}
		else if (pid == 0)
		{
			close(file);
			exit(0);
		}
		
		generate_graph(stats);
		
		// Libération de la mémoire allouée pour les statistiques
		free_stats(stats);
	}
	else
	{
		printf("* No packets captured, no statistics or graph !\n");
	}
	
	pcap_close(handle);
	
	free(str_addr);
	free(str_mask);
		
	return 0;
}

